import types
from pathlib import Path
import pytest
from _pytest.python import Module
import yaml
from config import settings
from utils.yaml_runner_handler import YamlRunner
from utils.extract_data_handler import extract_by_regex
from utils.db_handler import db


@pytest.fixture(scope="session", autouse=True)
def clear_extract_file():
    with open(settings.EXTRACT_RES_FILE_PATH, mode='w') as f:
        f.truncate()


@pytest.fixture(scope="session", autouse=True)
def clear_db_tables():
    db.get_conn_cursor()
    db.exec("set foreign_key_checks = 0")
    for table in settings.TABLES:
        db.exec(f"truncate table {table}")
    db.exec("set foreign_key_checks = 1")
    yield
    db.close_conn_cursor()


def pytest_collect_file(file_path: Path, parent):
    if file_path.suffix in [".yaml", ".yml"] and file_path.name.startswith("test"):
        pytest_module = Module.from_parent(parent, path=file_path)
        # 动态创建 module
        module = types.ModuleType(file_path.stem)
        # 解析 yaml 内容
        case_list = yaml.safe_load(file_path.open(encoding='utf-8'))
        runner = YamlRunner(case_list, module)
        runner.run()

        pytest_module._getobj = lambda: module  # noqa
        return pytest_module


def pytest_generate_tests(metafunc):  # noqa
    """测试用例参数化功能实现"""
    func_name = metafunc.function.__name__.split("_")[1]
    if hasattr(metafunc.module, func_name):
        params_data = getattr(metafunc.module, func_name)
        params_len = 0  # 参数化 参数的个数
        if isinstance(params_data, list):
            if isinstance(params_data[0], list):
                params_len = len(params_data[0])
            elif isinstance(params_data[0], dict):
                params_len = len(params_data[0].keys())
            else:
                params_len = 1
        # 安装了faker模块之后，metafunc.fixturenames多了一个request，跟_session_faker目前暂时先移除规避
        metafunc.fixturenames.remove("request")
        metafunc.fixturenames.remove("_session_faker")
        params_args = metafunc.fixturenames[-params_len:]
        if len(params_args) == 1:
            if not isinstance(params_data[0], list):
                params_data = [[p] for p in params_data]
        metafunc.parametrize(
            params_args,
            params_data,
            scope="function"
        )


def pytest_collection_modifyitems(session, config, items):
    # item表示每个测试用例，解决用例名称中文显示问题
    for item in items:
        item._nodeid = item._nodeid.encode("utf-8").decode("unicode-escape")
        item._nodeid = extract_by_regex(item._nodeid, r"(.*?)-")
        if isinstance(item._nodeid, list):
            item._nodeid = item._nodeid[0] + "]"
        else:
            item._nodeid = item._nodeid + "]"
